package ch.sv7.tool.dbmanager.db;

import java.sql.DatabaseMetaData;
import java.sql.Types;

import junit.framework.TestCase;
import ch.sv7.tool.dbmanager.db.difference.ColumnAutoIncrementDifference;
import ch.sv7.tool.dbmanager.db.difference.ColumnDefaultValueDifference;
import ch.sv7.tool.dbmanager.db.difference.ColumnJDBCTypeDifference;
import ch.sv7.tool.dbmanager.db.difference.ColumnSizeTooBigDifference;
import ch.sv7.tool.dbmanager.db.difference.ExtraColumnDifference;
import ch.sv7.tool.dbmanager.db.difference.ExtraConstraintDifference;
import ch.sv7.tool.dbmanager.db.difference.ExtraForeignKeyDifference;
import ch.sv7.tool.dbmanager.db.difference.SchemaDifferences;

/**
 *
 * @author svt
 *
 */
public class DifferencesTestCase extends TestCase {

	private TableSchema original;
	private TableSchema modified;
	
	protected void setUp() throws Exception {
		super.setUp();
		
		TableSchema ts = new TableSchema("mytable", null);
		ColumnType ct = new ColumnType(Types.INTEGER, 0, ColumnType.NO_SIZE_PROVIDED, true, false, null, null);
		ColumnSchema cs = new ColumnSchema(ts, "id" , ct, true);
		ts.addColumnSchema(cs);
		ct = new ColumnType(Types.VARCHAR, 20, ColumnType.NO_SIZE_PROVIDED, true, false, null, null);
		cs = new ColumnSchema(ts, "name" , ct, false);
		ts.addColumnSchema(cs);
		ct = new ColumnType(Types.VARCHAR, 20, ColumnType.NO_SIZE_PROVIDED, true, false, null, "def");
		cs = new ColumnSchema(ts, "name-def" , ct, false);
		ts.addColumnSchema(cs);
		
		original = ts;
		
		ts = new TableSchema("mytable", null);
		ct = new ColumnType(Types.INTEGER, 0, ColumnType.NO_SIZE_PROVIDED, true, false, null, null);
		cs = new ColumnSchema(ts, "id" , ct, true);
		ts.addColumnSchema(cs);
		ct = new ColumnType(Types.VARCHAR, 20, ColumnType.NO_SIZE_PROVIDED, true, false, null, null);
		cs = new ColumnSchema(ts, "name" , ct, false);
		ts.addColumnSchema(cs);
		ct = new ColumnType(Types.VARCHAR, 20, ColumnType.NO_SIZE_PROVIDED, true, false, null, "def");
		cs = new ColumnSchema(ts, "name-def" , ct, false);
		ts.addColumnSchema(cs);
		
		modified = ts;
		
	}

	public void testNoDifferences() throws Exception {
		SchemaDifferences diffs = new SchemaDifferences();
		original.computeDifferencesFromActual(diffs, modified);
		assertNotNull(diffs);
		assertEquals(0, diffs.getSize());
	}
	
	public void testTypeDifference() throws Exception {
		SchemaDifferences diffs = new SchemaDifferences();
		
		modified.getColumnSchema("id").getType().setJDBCType(Types.BIGINT);
		
		original.computeDifferencesFromActual(diffs, modified);
		assertNotNull(diffs);
		assertEquals(1, diffs.getSize());
		
		ColumnJDBCTypeDifference diff = (ColumnJDBCTypeDifference)diffs.getDifference(0);
		assertEquals("mytable", diff.getTableName());
		assertEquals("id", diff.getExpectedColumnSchema().getName());
		
		assertEquals("BIGINT", diff.getActualType().getJDBCTypeName());
		assertEquals("INTEGER", diff.getExpectedType().getJDBCTypeName());
	}
	
	public void testTypeSizeDifference() throws Exception {
		SchemaDifferences diffs = new SchemaDifferences();
		modified.getColumnSchema("id").getType().setSize(2);
		
		original.computeDifferencesFromActual(diffs, modified);
		assertNotNull(diffs);
		assertEquals(1, diffs.getSize());
		
		ColumnSizeTooBigDifference diff = (ColumnSizeTooBigDifference)diffs.getDifference(0);
		assertEquals("mytable", diff.getTableName());
		assertEquals("id", diff.getExpectedColumnSchema().getName());
		assertEquals("size", diff.getParam());
		assertEquals(0, diff.getExpectedSize());
		assertEquals(2, diff.getActualSize());
	}
	
	public void testDefaultValueDifference() throws Exception {
		SchemaDifferences diffs = new SchemaDifferences();
		
		modified.getColumnSchema("name-def").getType().setDefaultValue("toto");
		
		original.computeDifferencesFromActual(diffs, modified);
		assertNotNull(diffs);
		assertEquals(1, diffs.getSize());
		
		ColumnDefaultValueDifference diff = (ColumnDefaultValueDifference)diffs.getDifference(0);
		assertEquals("mytable", diff.getTableName());
		assertEquals("name-def", diff.getExpectedColumnSchema().getName());
		assertEquals("def", diff.getDefaultValue());
		assertEquals("toto", diff.getActualDefaultValue());
	}
	
	public void testAutoIncrementDifference() throws Exception {
		SchemaDifferences diffs = new SchemaDifferences();
		
		modified.getColumnSchema("id").getType().setAutoIncrement(true);
		
		original.computeDifferencesFromActual(diffs, modified);
		assertNotNull(diffs);
		assertEquals(1, diffs.getSize());
		
		ColumnAutoIncrementDifference diff = (ColumnAutoIncrementDifference)diffs.getDifference(0);
		assertEquals("mytable", diff.getTableName());
		assertEquals("id", diff.getExpectedColumnSchema().getName());
		assertEquals(false, diff.getExpectedColumnSchema().getType().isAutoIncrement());
	}

	public void testExtraColumnDifference() throws Exception {
		SchemaDifferences diffs = new SchemaDifferences();
		
		modified.addColumnSchema(new ColumnSchema(modified, "extra", modified.getColumnSchema("id").getType(),false));
		
		original.computeDifferencesFromActual(diffs, modified);
		assertNotNull(diffs);
		assertEquals(1, diffs.getSize());
		
		ExtraColumnDifference diff = (ExtraColumnDifference)diffs.getDifference(0);
		assertEquals("mytable", diff.getTableName());
		assertEquals(null, diff.getExpectedColumnSchema());
		assertEquals("extra", diff.getActualColumnSchema().getName());
	}

	public void testExtraConstraintDifference() throws Exception {
		SchemaDifferences diffs = new SchemaDifferences();
		
		modified.getConstraints().add(new ConstraintSchema(modified, "myConstraint", "myDefinition"));
		
		original.computeDifferencesFromActual(diffs, modified);
		assertNotNull(diffs);
		assertEquals(1, diffs.getSize());
		
		ExtraConstraintDifference diff = (ExtraConstraintDifference)diffs.getDifference(0);
		assertEquals("mytable", diff.getTableName());
		assertEquals("myConstraint", diff.getConstraintSchema().getName());
		assertEquals("myDefinition", diff.getConstraintSchema().getDefinition());
	}

	public void testExtraForeignKeyDifference() throws Exception {
		SchemaDifferences diffs = new SchemaDifferences();
		
		modified.getForeignKeys().add(
				new ForeignKeySchema(
						modified, 
						"myFk",
						"myColumns",
						"remoteTable",
						"remoteColumns",
						DatabaseMetaData.importedKeyNoAction,
						DatabaseMetaData.importedKeyNoAction,
						DatabaseMetaData.importedKeyNotDeferrable));
		
		original.computeDifferencesFromActual(diffs, modified);
		assertNotNull(diffs);
		assertEquals(1, diffs.getSize());
		
		ExtraForeignKeyDifference diff = (ExtraForeignKeyDifference)diffs.getDifference(0);
		assertEquals("mytable", diff.getTableName());
		assertEquals("myFk", diff.getForeignKey().getName());
		assertEquals("myColumns", diff.getForeignKey().getColumns());
	}

	protected void tearDown() throws Exception {
		super.tearDown();
	}

	
}
